﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Agility.TestProject.AppDriver;
using Agility.Web.Models.DomainModel;
using Agility.Web.Resources;
using Agility.Web.Repositories.EntityFramework;
using NLog;
using TechTalk.SpecFlow;
using Agility.Web.Models.RegistrationForm;
using System.Globalization;
using System.Web.Security;
using System.Web.Profile;

namespace Agility.TestProject.AppDriver
{
    public class AppDriverBase
    {
        string userName;
        AgilityRequirementsModelEntities requirementsEntities;
        EpicRepository epicRepo;
        List<Epic> testEpics;

        private static Logger logger = LogManager.GetCurrentClassLogger();

        public List<Epic> TestEpics 
        {
            get { return this.testEpics; }
            protected set { this.testEpics = value; } 
        }

        public string UserName 
        {
            get { return this.userName; }
            protected set { this.userName = value; } 
        }


        /// <summary>
        /// Creates a user and a repository for storing epics
        /// </summary>
        public virtual void Initialize()
        {
            logger.Debug("--> Entering Initialize");

            this.userName = this.CreateUser();
            logger.Debug("Created a user for this test");
            this.requirementsEntities = new AgilityRequirementsModelEntities();
            this.epicRepo = new EpicRepository(requirementsEntities);
            logger.Debug("Created EpicRepository");
            logger.Trace<EpicRepository>(epicRepo);
            this.testEpics = new List<Epic>();
            logger.Debug("<-- Leaving Initialize");
        }

        /// <summary>
        /// Cleans up users, roles and profiles and deletes all epics in the repository
        /// </summary>
        public virtual void Cleanup()
        {
            logger.Debug("--> Entering CleanUp");
            if (this.epicRepo != null)
            {
                IQueryable epics = this.epicRepo.GetEntities();
                foreach (Epic epic in epics)
                    this.epicRepo.Delete(epic);
                logger.Debug("Removed all epics from the database");
            }
            // Clean up the ASP.NET DB part of the repository
            MembershipUserCollection users = Membership.GetAllUsers();
            logger.Debug("Retrieved users");
            foreach (MembershipUser user in users)
            {
                try
                {
                    string[] assignedRoles = Roles.GetRolesForUser(user.UserName);
                    logger.Debug("Retrieved roles for user");
                    Roles.RemoveUserFromRoles(user.UserName, assignedRoles);
                    logger.Debug("Removed roles from user");
                }
                catch (Exception e)
                {
                    logger.WarnException(e.Message, e);
                }
                try
                {
                    ProfileManager.DeleteProfile(user.UserName);
                    logger.Debug("Deleted profile for user");
                }
                catch (Exception e)
                {
                    logger.WarnException(e.Message, e);
                }
                try
                {
                    Membership.DeleteUser(user.UserName);
                    logger.Debug("Deleted user");
                }
                catch (Exception e)
                {
                    logger.WarnException(e.Message, e);
                }
            }
            string[] allRoles = Roles.GetAllRoles();
            logger.Debug("Retrieved all roles");
            for (int i = 0; i < allRoles.Length; i++)
            {
                try
                {
                    Roles.DeleteRole(allRoles[i]);
                    logger.Debug("Deleted role {0}", allRoles[i]);
                }
                catch (Exception e)
                {
                    logger.WarnException(e.Message, e);
                }
            }
            logger.Debug("<-- Leaving Cleanup");
        }

        /// <summary>
        /// Creates a user in the database as Registered User and sets the UserName property if successful
        /// </summary>
        public string CreateUser()
        {
            logger.Debug("--> Entering CreateUser");
            string userName = Guid.NewGuid().ToString();
            RegistrationData regData = new RegistrationData();
            regData.Answer = "Nothing much";
            regData.Email = string.Format(CultureInfo.InvariantCulture, "{0}@testing.com", userName);
            regData.FriendlyName = "Dave";
            regData.Question = "What's up?";
            regData.UserName = userName;
            Agility.Testing.Web.UserRegistrationServiceReference.UserRegistrationServiceSoap userRegistrationClient = new Agility.Testing.Web.UserRegistrationServiceReference.UserRegistrationServiceSoapClient();
            Agility.Web.Services.CreateUserStatus status = userRegistrationClient.CreateUser(regData, "Test##100");
            if (status == Web.Services.CreateUserStatus.Success)
            {
                logger.Debug("<-- Leaving CreateUser returning {0}", userName);
                return userName;
            }
            else
            {
                logger.Debug("<-- Leaving CreateUser string.Emtpy");
                return string.Empty;
            }
        }

        /// <summary>
        /// Verifies that the user has a role assigend
        /// </summary>
        /// <param name="roleName">the role to check for</param>
        /// <returns></returns>
        public bool IsInRole(string roleName)
        {
            // TODO: as soon as there are more roles than Registered User this method must be able to verify the roles a user has
            //if (!qryUser.RootResults[0].Roles.Contains(roleName))
            //    ;
            return true;
        }

        /// <summary>
        /// Assigns a role to the user
        /// </summary>
        /// <param name="roleName">the name of the role</param>
        public void AssignRole(string roleName)
        {
            // TODO: as soon as there are more roles than Registered User this method must be able to assign roles to users
        }

        /// <summary>
        /// Creates dummy epics to test with
        /// </summary>
        public void CreateEpicsForMyIdeas()
        {
            logger.Debug("--> Entering CreateEpicsForMyIdeas");
            
            Epic e1 = Epic.CreateEpic(Guid.NewGuid(), "Manage Requirements", "Create, review/display, update and delete epics", DateTime.Today.AddDays(-1), this.userName);
            logger.Debug("Created the epic");
            logger.Trace<Epic>(e1);
            this.epicRepo.Insert(e1);
            logger.Debug("Added the epic to the repository");
            logger.Trace<EpicRepository>(this.epicRepo);
            this.epicRepo.Save();
            logger.Debug("Saved changes to the database");
            this.testEpics.Add(e1);
            logger.Debug("Added the epic to the local collection");
            Epic e2 = Epic.CreateEpic(Guid.NewGuid(), "Plan Implementation", "Plan in which release and sprint a story will be implemented", DateTime.Today.AddDays(-1), this.userName);
            logger.Debug("Created the epic");
            logger.Trace<Epic>(e2);
            this.epicRepo.Insert(e2);
            logger.Debug("Added the epic to the repository");
            logger.Trace<EpicRepository>(this.epicRepo);
            this.requirementsEntities.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
            logger.Debug("Saved changes to the database");
            this.testEpics.Add(e2);
            logger.Debug("Added the epic to the local collection");
            Epic e3 = Epic.CreateEpic(Guid.NewGuid(), "Execute Implementation", "Plan implementation of tasks in a sprint and provide reports on progress of Sprints, Release, and Epics", DateTime.Today, this.userName);
            logger.Debug("Created the epic");
            logger.Trace<Epic>(e3);
            this.epicRepo.Insert(e3);
            logger.Debug("Added the epic to the repository");
            logger.Trace<EpicRepository>(this.epicRepo);
            this.requirementsEntities.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
            logger.Debug("Saved changes to the database");
            this.testEpics.Add(e3);
            logger.Debug("Added the epic to the local collection");
            Epic e4 = Epic.CreateEpic(Guid.NewGuid(), "Someone else's Epic", "Some other epic requested by a different user", DateTime.Today, Guid.NewGuid().ToString());
            logger.Debug("Created the epic");
            logger.Trace<Epic>(e4);
            this.epicRepo.Insert(e4);
            logger.Debug("Added the epic to the repository");
            logger.Trace<EpicRepository>(this.epicRepo);
            this.requirementsEntities.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
            logger.Debug("Saved changes to the database");
            this.testEpics.Add(e4);
            logger.Debug("Added the epic to the local collection");
            logger.Debug("<-- Leaving CreateEpicsForMyIdeas");
        }
    }
}
